package calcs;

import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
import static util.UserInputChecker.checkInput;
import static util.UserInputChecker.setCalculated;
import static util.UserInputChecker.setInitial;
import static util.Util.roundToDecimals;
import gui.ErrorMessage;
import gui.MyFrame;
import gui.data.D3.PyramidOutputGui;

public class PyramidCalculator extends Thread {
	double volume, bArea, sArea, area, sHeight, height, side;
	boolean found = false, before = false, calculated = false;
	MyFrame myFrame;

	public PyramidCalculator(double volume, double area, double bArea,
			double sArea, double sHeight, double height, double side,
			final MyFrame myFrame) {
		this.volume = volume;
		this.area = area;
		this.bArea = bArea;
		this.sArea = sArea;
		this.sHeight = sHeight;
		this.height = height;
		this.side = side;
		this.myFrame = myFrame;
		setInitial(volume, bArea, sArea, area, sHeight, height, side);
		start();
	}

	public PyramidCalculator(double volume, double area, double bArea,
			double sArea, double sHeight, double height, double side) {
		this.volume = volume;
		this.area = area;
		this.bArea = bArea;
		this.sArea = sArea;
		this.sHeight = sHeight;
		this.height = height;
		this.side = side;
	}

	public void run() {
		do {
			found = false;
			before = false;
			calculated = false;

			before = volume != 0;
			calculateVolume();
			if (!before && found) {
				calculated = true;
			}

			before = area != 0;
			calculateArea();
			if (!before && found) {
				calculated = true;
			}

			before = sArea != 0;
			calculateSideArea();
			if (!before && found) {
				calculated = true;
			}

			before = bArea != 0;
			calculateBottomArea();
			if (!before && found) {
				calculated = true;
			}

			before = sHeight != 0;
			calculateSideHeight();
			if (!before && found) {
				calculated = true;
			}

			before = height != 0;
			calculateHeight();
			if (!before && found) {
				calculated = true;
			}

			before = side != 0;
			calculateSide();
			if (!before && found) {
				calculated = true;
			}
		} while (calculated);
		finish();
	}

	private void finish() {
		volume = roundToDecimals(volume, 2);
		area = roundToDecimals(area, 2);
		side = roundToDecimals(side, 2);
		bArea = roundToDecimals(bArea, 2);
		sArea = roundToDecimals(sArea, 2);
		sHeight = roundToDecimals(sHeight, 2);
		height = roundToDecimals(height, 2);
		if (myFrame != null) {
			setCalculated(volume, bArea, sArea, area, sHeight, height, side);
			if (checkInput()) {
				myFrame.setDataPanel(new PyramidOutputGui(volume, area, bArea,
						sArea, sHeight, height, side), "PYRAMID_OUTPUT");
			} else {
				new ErrorMessage("Check input");
			}
		}
	}

	private void calculateSide() {
		if (bArea != 0) {
			side = sqrt(bArea);
			found = true;
		} else if (volume != 0 && height != 0) {
			side = sqrt((3 * volume) / height);
			found = true;
		} else if (sArea != 0 && sHeight != 0) {
			side = sArea / (2 * sHeight);
			found = true;
		} else if (height != 0 && sHeight != 0) {
			side = 2 * sqrt(pow(sHeight, 2) - pow(height, 2));
			found = true;
		}
	}

	private void calculateHeight() {
		if (side != 0) {
			if (volume != 0) {
				height = (3 * volume) / pow(side, 2);
				found = true;
			} else if (sArea != 0) {
				height = sqrt(pow(sArea / side, 2) - pow(side, 2)) / 2;
				found = true;
			} else if (sHeight != 0) {
				height = sqrt(pow(sHeight, 2) - (pow(side, 2) / 4));
				found = true;
			}
		}
	}

	private void calculateSideHeight() {
		if (side != 0) {
			if (height != 0) {
				sHeight = sqrt(pow(height, 2) + (pow(side, 2) / 4));
				found = true;
			} else if (sArea != 0) {
				sHeight = sArea / (2 * side);
				found = true;
			}
		}

	}

	private void calculateBottomArea() {
		if (side != 0) {
			bArea = pow(side, 2);
			found = true;
		} else if (area != 0 && sArea != 0) {
			bArea = area - sArea;
			found = true;
		}
	}

	private void calculateSideArea() {
		if (area != 0 && bArea != 0) {
			sArea = area - bArea;
			found = true;
		} else if (side != 0) {
			if (height != 0) {
				sArea = side * sqrt((4 * pow(height, 2)) + pow(side, 2));
				found = true;
			} else if (sHeight != 0) {
				sArea = 2 * side * sHeight;
				found = true;
			}
		}
	}

	private void calculateArea() {
		if (sArea != 0 && bArea != 0) {
			area = sArea + bArea;
			found = true;
		}
	}

	private void calculateVolume() {
		if (height != 0 && side != 0) {
			volume = (height * pow(side, 2)) / 3;
			found = true;
		}
	}

}
